package org.softmed.neodatis.util.id;

import org.neodatis.odb.ODB;
import org.neodatis.odb.OID;
import org.neodatis.odb.Objects;
import org.neodatis.odb.core.trigger.InsertTrigger;
import org.softmed.neodatis.util.id.generator.IDGenerator;
import org.softmed.neodatis.util.provider.ODBProvider;
import org.softmed.neodatis.util.reflection.ClassIDFieldRegistration;
import org.softmed.neodatis.util.trigger.CloneableInsertTrigger;
import org.softmed.reflection.utils.FieldInfo;
import org.softmed.reflection.utils.ReflectionUtil;

public class GenerateIDTrigger extends InsertTrigger {

	ReflectionUtil rutil = new ReflectionUtil();
	ClassFieldIDGenerators classFieldIDGenerators;
	ClassIDFieldRegistration classIDFieldRegistration = new ClassIDFieldRegistration();
	ClassFieldIDProcessor processor = new ClassFieldIDProcessor();

	// public GenerateIDTrigger(String providerName) {
	// this.providerName = providerName;
	// provider = nodb.getProvider(providerName);
	// }

	public void getStoredGenerators(ODB odb) throws Throwable {
		Objects objects = odb.getObjects(ClassFieldIDGenerators.class);

		ClassFieldIDGenerators storedGenerators = null;
		if (objects.hasNext())
			storedGenerators = (ClassFieldIDGenerators) objects.next();

		if (storedGenerators == null) {
			storedGenerators = new ClassFieldIDGenerators();
		}
		classFieldIDGenerators = storedGenerators;

	}

	public void storeGenerators(ODB odb) throws Throwable {
		odb.store(classFieldIDGenerators);
	}

	public void afterInsert(Object object, OID oid, long position) {
		if (object.getClass() == this.getClass()
				|| object.getClass() == ClassFieldIDGenerators.class)
			return;

	}

	// public boolean beforeInsert(Object object) throws Throwable {
	// if (object.getClass() == this.getClass()
	// || object.getClass() == ClassFieldIDGenerators.class)
	// return false;
	//
	// processor.process(classIDFieldRegistration, classFieldIDGenerators,
	// object);
	//
	// // System.out.println("before inserting " + object);
	// return true;
	// }

	public GenerateIDTrigger clone() {
		GenerateIDTrigger clone = new GenerateIDTrigger();
		return clone;
	}

	public ClassFieldIDGenerators getClassFieldIDGenerators() {
		return classFieldIDGenerators;
	}

	public void setClassFieldIDGenerators(ClassFieldIDGenerators ids) {
		this.classFieldIDGenerators = ids;
	}

	public ClassIDFieldRegistration getClassIDFieldRegistration() {
		return classIDFieldRegistration;
	}

	protected void registerGenerator(ODBProvider provider, Class type,
			String fieldName, IDGenerator generator, boolean replace)
			throws Throwable {

		FieldInfo fieldInfo = rutil.getFieldInfo(type, fieldName);
		if (fieldInfo == null)
			throw new RuntimeException("The class " + type
					+ " has no field named " + fieldName
					+ ". Can't register generator.");

		ODB odb = null;
		try {
			odb = provider.getODB();
			getStoredGenerators(odb);
			classFieldIDGenerators.registerGenerator(type, fieldName,
					generator, replace);
			classIDFieldRegistration.register(type, fieldName);
			storeGenerators(odb);
			odb.close();
		} catch (Throwable e) {
			e.printStackTrace();
			if (odb != null) {
				try {
					odb.close();
					odb = null;
				} catch (Exception t) {
					t.printStackTrace();
				}
			}
		}

	}

	public void disableAllInheritedGeneratedFields(Class type) {
		classIDFieldRegistration.disableAllInheritedGeneratedFields(type);
	}

	public void disableInheritedGeneratedField(Class type, String fieldName)
			throws Throwable {
		classIDFieldRegistration
				.disableInheritedGeneratedField(type, fieldName);
	}

	public void replaceGenerator(ODBProvider provider, Class type,
			String fieldName, IDGenerator generator) throws Throwable {
		registerGenerator(provider, type, fieldName, generator, true);
	}

	public void registerGenerator(ODBProvider provider, Class type,
			String fieldName, IDGenerator generator) throws Throwable {
		registerGenerator(provider, type, fieldName, generator, false);
	}

	@Override
	public void afterInsert(Object arg0, OID arg1) {

		try {
			storeGenerators(getOdb());
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public boolean beforeInsert(Object object) {
		if (object.getClass() == this.getClass()
				|| object.getClass() == ClassFieldIDGenerators.class)
			return false;

		try {
			getStoredGenerators(getOdb());
		} catch (Throwable e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		try {
			processor.process(classIDFieldRegistration, classFieldIDGenerators,
					object);
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// System.out.println("before inserting " + object);
		return true;
	}

}
